package com.darwin.darwinDisplay
{
	import com.darwin.darwinImage.darx.DarX;
	
	import flash.display.BitmapData;
	import flash.filters.BitmapFilter;
	import flash.filters.GlowFilter;
	import flash.geom.Matrix;
	import flash.utils.Dictionary;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;

	/**
	 *	DarXBitmap动画缓存管理器
	 * @author Roland
	 * 
	 */
	public class DarXBitmapManager
	{
		/**
		 *	资源失去所有引用后的保留时间，超过此时间如果没有新的引用则将销毁其对应的动画序列 (毫秒)
		 */
		public static const DESTROY_DELAY_TIME:int = 2000;
		
		private var timeOutId:uint = 0;

		/**
		 *	缓存保护字典，记录在此字典中的id对应的数据不会被对象池回收，将长期驻留内存
		 */
		private var _cacheProtectDic:Dictionary;
		
		/**
		 *	 已经绘制过的组合动画序列引用计数,当计数为0时,则将在经过保留时间之后彻底销毁对应动画序列
		 */
		private var _quoteCombinDic:Dictionary;
		
		/**
		 *	darXBitmapData实例在组合动画中的引用计数 
		 */
		private var _quoteDarXBitmapDataDic:Dictionary;
		
		/**
		 *	缓存组合列表的字典 
		 */
		private var _darXCombinListDic:Dictionary;

		/**
		 *	DarXBitmapData缓存字典
		 */
		private var _darXBitmapDataDic:Dictionary;
		/**
		 *	实例化 
		 */
		public function DarXBitmapManager()
		{
			if(_instance)
			{
				throw new Error("实例化单例DarXBitmapManager出错");
			}else{
				_cacheProtectDic = new Dictionary();
				_darXCombinListDic = new Dictionary();
				_darXBitmapDataDic = new Dictionary();
				_quoteCombinDic = new Dictionary();
				_quoteDarXBitmapDataDic = new Dictionary();
			}
		}
		
		private static var _instance:DarXBitmapManager;
		public static function getInstance():DarXBitmapManager
		{
			if(_instance == null)
			{
				_instance = new DarXBitmapManager();
			}
			return _instance;
		}
		
		/**
		 *	开启对指定对象的缓存保护
		 * <br/>被设定为缓存保护的动画数据不会对象池回收，将长期驻留内存。
		 * <br/>此选项主要用于那些游戏过程中永远无需回收的对象(如RPG游戏中的主人公Avatar等) 
		 * @param param 要开启保护的对象
		 * <li/>如果要保护单个DarXBitmapData对象，直接传此对象作为参数：
		 * <br/>setCacheProtect(darXBitmapData:DarXBitmapData);
		 * <li/>如果要保护一组DarXBitmapData合并而成的组合动画数据，可按如下方式传参：
		 * <br/>setCacheProtect(list:Vector.< DarXBitmapData >,matrix:Matrix = null,filtersList:Vector.<BitmapFilterList> = null);
		 */
		public function setCacheProtect(...param):void
		{
			var item:* = param[0];
			var id:String = "";
			if(item is DarXBitmapData)
			{
				id = (item as DarXBitmapData).darXID.toString();
			}else if(item is Vector.<DarXBitmapData>)
			{
				param.length = 3;
				id = getSignatureId(param[0],param[1],param[2]);
			}
			if(id != "")
			{
				_cacheProtectDic[id] = param;
			}
		}
		
		/**
		 *	取消对指定对象的缓存保护
		 * <br/>被取消缓存保护的对象如果其引用次数已经<=0，则将在下一次检查时被对象池回收 
		 * @param param 要取消保护的对象，参数填写方式参照setCacheProtect方法
		 * @see setCacheProtect
		 * 
		 */
		public function cancelCacheProtect(...param):void
		{
			var item:* = param[0];
			var id:String = "";
			if(item is DarXBitmapData)
			{
				id = (item as DarXBitmapData).darXID.toString();
			}else if(item is Vector.<DarXBitmapData>)
			{
				param.length = 3;
				id = getSignatureId(param[0],param[1],param[2]);
			}
			if(id != "")
			{
				delete _cacheProtectDic[id];
			}
		}
		
		/**
		 *	绘制单个darXBitmap
		 * @param darx
		 * @param compFn  绘制完成后的回调函数 function compFn(bitmapDataList:Array,frameOffsetList:Array):void
		 */
		public function drawDarXBitmapData(darx:DarXBitmapData,compFn:Function):void
		{
			if(_darXBitmapDataDic[darx])
			{
				addSingleQuote(darx);
				if(compFn != null)
				{
					compFn(darx.frameList,darx.frameOffsetList);
				}
			}else{
				DarX.decodeDarXBitmapData(darx,onDecodeComplete);
			}
			function onDecodeComplete(data:DarXBitmapData):void
			{
				addSingleQuote(data);
				if(compFn != null)
				{
					var frames:Array = [];
					var offsets:Array =  [];
					for (var i:int = 0; i < data.frameList.length; i++) 
					{
						frames.push(data.frameList[i]);
						offsets.push(data.frameOffsetList[i]);
					}
					compFn(frames,offsets);
				}
			}
		}
		
		/**
		 *	将传入的 DarXBitmapData动画列表合并绘制为一份动画序列
		 * @param list
		 * @param compFn 绘制完成后的回调函数  function compFn(bitmapDataList:Array,frameOffsetList:Array):void
		 * @param matrix 要对动画应用的矩阵变换
		 * @param filtersList 要给列表中每部件单独应用的滤镜列表(可选)
		 */
		public function drawDarxBitmapDataList(list:Vector.<DarXBitmapData>,compFn:Function,matrix:Matrix = null,filtersList:Vector.<BitmapFilterList> = null):void
		{
			var sId:String = getSignatureId(list,matrix,filtersList);
//			trace(sId);
			var cacheddata:Object = _darXCombinListDic[sId];
			if(cacheddata)//如果已经缓存过了，直接返回
			{
				if(compFn!=null)
				{
					addCombinQuote(list,matrix,filtersList);//引用加1;
					compFn(cacheddata["frames"],cacheddata["offsets"]);
				}
			}else{
				DarX.decodeDarXBitmapDataList(list,decodeComplete);
			}
			
			function decodeComplete(darxList:Vector.<DarXBitmapData>):void
			{
				DarX.synthesis(darxList,synthesieComplete,filtersList,matrix);
			}
			
			function synthesieComplete(bitmapDataList:Array,frameOffsetList:Array):void
			{
				_darXCombinListDic[sId] = {"frames":bitmapDataList , "matrix":matrix , "offsets":frameOffsetList};
				for (var i:int = 0; i < list.length; i++) 
				{
					var id:uint = list[i].darXID;
					_darXBitmapDataDic[id] = list[i];
				}
				if(compFn!=null)
				{
					addCombinQuote(list,matrix,filtersList);//引用加1;
					compFn(bitmapDataList,frameOffsetList);
				}
			}
		}
		
		//================================
		//					特侦码生成
		//==================================
		/**
		 *	获取DarXBitmapData列表和变换矩阵组合的唯一特征码, 内容完全一致的列表和矩阵组合将始终返回相同的特征码
		 * @param list
		 * @param matrix
		 * @return 
		 * 
		 */
		private function getSignatureId(list:Vector.<DarXBitmapData>,matrix:Matrix = null,filtersList:Vector.<BitmapFilterList> = null):String
		{
			var codeArr:Array = [];
			var sortedListArr:Array = [];
			for (var i:int = 0; i < list.length; i++) 
			{
				sortedListArr.push({"id":list[i].darXID,"data":list[i],"filters":filtersList ? filtersList[i] : null});
			}
			sortedListArr.sortOn("id",Array.NUMERIC);		
			codeArr.push(getListIdCode(sortedListArr),getMatrixIdCode(matrix),getBitmapFilterListIdCode(sortedListArr));
			return codeArr.join("#");
		}
		
		private function getListIdCode(sortedListArr:Array):String
		{
			var arr:Array = [];
			for (var i:int = 0; i < sortedListArr.length; i++) 
			{
				arr.push(sortedListArr[i].id);
			}
			return arr.join(":");
		}
		
		private function getMatrixIdCode(matrix:Matrix):String
		{
			if(matrix == null) matrix = new Matrix();
			return [matrix.a,matrix.b,matrix.c,matrix.d,matrix.tx,matrix.ty].join(":");
		}
		
		private function getBitmapFilterListIdCode(sortedListArr:Array):String
		{
			var arr:Array = [];
			for (var k:int = 0; k < sortedListArr.length; k++) 
			{
				var list:BitmapFilterList = sortedListArr[k].filters;
				if(list && list.filtersVec)
				{
					var vec:Vector.<BitmapFilter>= list.filtersVec;
					var fArr:Array = [];
					for (var i:int = 0; i < vec.length; i++) 
					{
						fArr.push(getBitmapFilterIdCode(vec[i]));
					}
					arr.push(fArr.join("|"));
				}else{
					arr.push("null");
				}
			}
			return arr.join(":");

		}
		
		private function getBitmapFilterIdCode(filter:BitmapFilter):String
		{
			if(filter is GlowFilter)
			{
				var g:GlowFilter = filter as GlowFilter;
				return [g.alpha,g.blurX,g.blurY,g.color,g.inner,g.knockout,g.quality,g.strength].join(",");
			}
			return "null";
		}
		//================================
		//					资源管理
		//==================================
		
		/**
		 *	对单个darxBitmapData实例增加一次引用 
		 * @param darxBitmapData
		 * 
		 */
		public function addSingleQuote(darxBitmapData:DarXBitmapData):void
		{
			if(_quoteDarXBitmapDataDic[darxBitmapData.darXID] == null)
			{
				_quoteDarXBitmapDataDic[darxBitmapData.darXID] = 1;
			}else{
				_quoteDarXBitmapDataDic[darxBitmapData.darXID] ++;
			}
		}
		
		/**
		 *	对单个darxBitmapData实例减少一次引用 
		 * @param darxBitmapData
		 * @param checkAfterReduce 删除引用后是否检查并销毁无引用资源
		 */
		public function reduceSingleQuote(darxBitmapData:DarXBitmapData,checkAfterReduce:Boolean = true):void
		{
			if(_quoteDarXBitmapDataDic[darxBitmapData.darXID])
			{
				_quoteDarXBitmapDataDic[darxBitmapData.darXID] --;
			}
			if(checkAfterReduce)
			{
				//延时销毁
				clearTimeout(timeOutId);//停止上一次延时，重新计时
				timeOutId = setTimeout(checkAndDestoryQuote,DESTROY_DELAY_TIME);
			}
		}
		
		/**
		 *	对组合动画资源增加一次引用 ，同时会对list参数中每个darXBitmapData实例单独添加一次引用(addSingleQuote)
		 * 
		 */
		public function addCombinQuote(list:Vector.<DarXBitmapData>,matrix:Matrix,filtersList:Vector.<BitmapFilterList> = null):void
		{
			var sId:String = getSignatureId(list,matrix,filtersList);
			//对单个darXBitmapData添加引用
			for (var i:int = 0; i < list.length; i++) 
			{
				addSingleQuote(_darXBitmapDataDic[list[i].darXID]);
			}
			//对组合列表添加引用
			if(_quoteCombinDic[sId] == null)
			{
				_quoteCombinDic[sId] = 1;
			}else{
				_quoteCombinDic[sId] ++;
			}
		}
		
		
		/**
		 *	对组合动画资源减少一次引用 ，同时会对list参数中每个darXBitmapData实例单独减少一次引用(reduceSingleQuote)
		 */
		public function reduceCombinQuote(list:Vector.<DarXBitmapData>,matrix:Matrix,filtersList:Vector.<BitmapFilterList> = null):void
		{
			var sId:String = getSignatureId(list,matrix,filtersList);
			//对单个darXBitmapData减少引用
			for (var i:int = 0; i < list.length; i++) 
			{
				if(_darXBitmapDataDic[list[i].darXID])
				{
					reduceSingleQuote(_darXBitmapDataDic[list[i].darXID],false);
				}
			}
			//对组合列表减少引用
			if(_quoteCombinDic[sId])
			{
				_quoteCombinDic[sId] -- ;
			}
			
			//延时销毁
			clearTimeout(timeOutId);//停止上一次延时，重新计时
			timeOutId = setTimeout(checkAndDestoryQuote,DESTROY_DELAY_TIME);
		}
		
		
		/**
		 *	检查资源引用情况，销毁已经没有引用的资源动画
		 * 
		 */
		private function checkAndDestoryQuote():void
		{
			for(var sId:String in _quoteCombinDic) 
			{
				if(_cacheProtectDic[sId] != null) continue;
				if(_quoteCombinDic[sId] <= 0)
				{
					var cachedData:Object = _darXCombinListDic[sId];
					var frames:Array = cachedData["frames"];
					for (var i:int = 0; i < frames.length; i++) 
					{
						var bitmapData:BitmapData = frames[i];
						bitmapData.dispose();
					}
					delete _darXCombinListDic[sId];
					delete _quoteCombinDic[sId];
//					trace("销毁组合动画资源,sId："+sId);
				}
			}
			
			for(var darXID:String in _quoteDarXBitmapDataDic)
			{
				if(_cacheProtectDic[darXID] != null) continue;
				if(_quoteDarXBitmapDataDic[darXID] <= 0)
				{
					var cachedDarX:DarXBitmapData = _darXBitmapDataDic[darXID];
					if(cachedDarX)
					{
						if(cachedDarX.frameList)
						{
							for (var j:int = 0; j < cachedDarX.frameList.length; j++) 
							{
								cachedDarX.frameList[j].dispose();
							}
							cachedDarX.frameList = null;
						}
						if(cachedDarX.zMapList)
						{
							for (var k:int = 0; k < cachedDarX.zMapList.length; k++) 
							{
								cachedDarX.zMapList[k].dispose();
							}
							cachedDarX.zMapList = null;
						}
						delete _darXBitmapDataDic[darXID];
						delete _quoteDarXBitmapDataDic[darXID];
//						trace("销毁darXBitmapData位图数据,darXID:" + darXID)
					}
				}
			}
		}
	}
}